/**
 *
 */
package jp.seraph.same.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.NullArgumentException;

import jp.seraph.jsade.model.Joint;
import jp.seraph.jsade.model.JointIdentifier;
import jp.seraph.jsade.model.JointIdentifierContainer;
import jp.seraph.jsade.model.ObjectContainer;
import jp.seraph.jspf.pose.DefaultPose;
import jp.seraph.jspf.pose.Pose;

/**
 * 
 */
public class DefaultPoseModel implements PoseModel {
    public DefaultPoseModel(ObjectContainer aContainer, JointIdentifierContainer aIdentifierContainer, JointPositionMapper aPositionMapper, DefaultPose aPose) {
        mObjectContainer = aContainer;
        mPose = aPose;
        mListeners = new ArrayList<PoseModelListener>();
        mIdentifiers = new ArrayList<JointIdentifier>();
        mSelectedIndex = 0;
        mIdentifierContainer = aIdentifierContainer;
        for (JointIdentifier tIdentifier : aIdentifierContainer) {
            mIdentifiers.add(tIdentifier);
        }

        this.initializeJointPosition(aPositionMapper);
    }

    private void initializeJointPosition(JointPositionMapper aPositionMapper) {
        mJointPositionMap = new HashMap<JointIdentifier, JointPositionEntry>();
        for (JointIdentifier tIdentifier : mIdentifiers) {
            mJointPositionMap.put(tIdentifier, aPositionMapper.getPosition(tIdentifier));
        }
    }

    private ObjectContainer mObjectContainer;
    private DefaultPose mPose;
    private List<PoseModelListener> mListeners;
    private List<JointIdentifier> mIdentifiers;
    private Map<JointIdentifier, JointPositionEntry> mJointPositionMap;
    private int mSelectedIndex;
    private JointIdentifierContainer mIdentifierContainer;

    /**
     * 
     * @see jp.seraph.same.model.PoseModel#addListener(jp.seraph.same.model.PoseModelListener)
     */

    public void addListener(PoseModelListener aListener) {
        if (aListener == null)
            throw new NullArgumentException("aListener");

        mListeners.add(aListener);
    }

    /**
     * 
     * @see jp.seraph.same.model.PoseModel#createPose()
     */

    public Pose createPose() {
        return new DefaultPose(mPose);
    }

    /**
     * 
     * @see jp.seraph.same.model.PoseModel#setPose(jp.seraph.jspf.pose.Pose)
     */

    public void setPose(Pose aPose) {
        mPose.modifyPose(aPose);
    }

    /**
     * 
     * @see jp.seraph.same.model.PoseModel#getJointCount()
     */

    public int getJointCount() {
        return mIdentifiers.size();
    }

    /**
     * 
     * @see jp.seraph.same.model.PoseModel#getJointModel(int)
     */

    public JointModel getJointModel(int aIndex) {
        return this.getJointModel(mIdentifiers.get(aIndex));
    }

    /**
     * 
     * @see jp.seraph.same.model.PoseModel#getJointModel(java.lang.String)
     */

    public JointModel getJointModel(String aJointName) {
        return this.getJointModel(mIdentifierContainer.getIdentifier(aJointName));
    }

    private JointModel getJointModel(JointIdentifier aIdentifier) {
        Joint tTarget = mObjectContainer.getJoint(aIdentifier);
        JointPositionEntry tEntry = mJointPositionMap.get(aIdentifier);
        return new PoseJointModel(mPose, aIdentifier, tEntry.getAlign(), tEntry.getOrder(), tTarget.getMaxAngle().getDegree(), tTarget.getMinAngle().getDegree());
    }

    /**
     * 
     * @see jp.seraph.same.model.PoseModel#getSelectedJointModel()
     */

    public JointModel getSelectedJointModel() {
        return this.getJointModel(mIdentifiers.get(mSelectedIndex));
    }

    /**
     * 
     * @see jp.seraph.same.model.PoseModel#getSelectedJointName()
     */

    public String getSelectedJointName() {
        return mIdentifiers.get(mSelectedIndex).toJointName();
    }

    /**
     * 
     * @see jp.seraph.same.model.PoseModel#removeListener(jp.seraph.same.model.PoseModelListener)
     */

    public boolean removeListener(PoseModelListener aListener) {
        int tCount = mListeners.size();
        for (int i = 0; i < tCount; i++) {
            if (mListeners.get(i).equals(aListener)) {
                mListeners.remove(i);
                return true;
            }
        }

        return false;
    }

    /**
     * 
     * @see jp.seraph.same.model.PoseModel#selectJoint(java.lang.String)
     */

    public void selectJoint(String aJointName) {
        int tIndex = mIdentifiers.indexOf(mIdentifierContainer.getIdentifier(aJointName));
        this.selectJoint(tIndex);
    }

    /**
     * 
     * @see jp.seraph.same.model.PoseModel#selectJoint(int)
     */

    public void selectJoint(int aIndex) {
        if (aIndex == mSelectedIndex)
            return;

        mSelectedIndex = aIndex;
        onSelectedJointChanged(aIndex);
    }

    protected void onSelectedJointChanged(int aIndex) {
        for (PoseModelListener tListener : mListeners) {
            tListener.SelectedJointChanged(this, aIndex);
        }
    }
}
